<?php
namespace Base;
use App;
use Cache\Redis;
use DB;
use Exception;
use Illuminate\Support\Str;
use Jwt\Token;
use JetBrains\PhpStorm\NoReturn;
use OperateLogModel;
use OrganizationModel;
use OrganizationUserModel;
use PermissionModel;
use Request;
use RoleHasOrganizationModel;
use RoleHasPermissionModel;
use RoleModel;
use UserModel;
use Yaf\Config\Ini;
use Yaf\Exception\TypeError;

/**
 * admin用户总控制器
 */
class AdminController extends BaseController
{
    /**
     * 含用户数据
     * @var array
     */
    protected array $token = [];

    /**
     * @var string 域名
     */
    protected string $host = "";

    /**
     * @var int 用户id
     */
    protected int $member_id;

    /**
     * 查询条件
     * @var array
     */
    protected array $where = [];

    /**
     * 查询条件 In
     * @var array
     */
    protected array $whereIn = [];

    /**
     * 查询条件闭包
     * @var object|null
     */
    protected ?object $whereFunction = null;

    /**
     * 查询includes
     * @var array
     */
    protected array $includes = [];

    /**
     * 模型名称
     * @var string
     */
    protected string $model="";

    /**
     * 表名
     * @var string
     */
    protected string $table = '';

    /**
     * 用户信息
     * @var mixed|null
     */
    protected mixed $user = null;

    /**
     * 组织机构信息
     * @var mixed|null
     */
    protected mixed $org = null;

    /**
     * 路由白名单
     * @var array
     */
    protected array $routeWhiteLst = [];

    /**
     * 是否开启查询条件作用域
     * @var bool
     */
    protected bool $scopeWhere =true;

    /**
     * 初始化
     */
    #[NoReturn] public function init(): void
    {
        $this->host = getRequestHost();
        try {
            Token::$prefix_refresh = "admin_refresh_token:";
            Token::$prefix_member = "admin_member_token:";
            //验证 token
            $resultToken = Token::verify();
            if($resultToken === false) $this->apiError(Token::get_msg(), Token::get_status());
            $this->member_id = $resultToken['member_id'];
            $this->token = $resultToken;
            $user = UserModel::query()->with(["role","organization"])->where("id",$this->member_id)->first();
            if (!$user) $this->apiError("账号异常");
            if ($user['is_hid']==1) {
                $this->apiError("账号已被禁用，请联系管理员");
            }
            if ($user->organization->isNotEmpty()) {
                $this->org = $user->organization[0];
            }
            $this->user = $user;
            //访问权限白名单
            $whiteLst = [
                'permission@getall','role@getall',
                'permission@getdata','user@modify',
                'upload@file', 'permission@getselectdata',
                'user@info','wechatmenu@getselectdata',
                'organization@orgtree',
                'category@getoptions', strtolower( $this->getRequest()->getControllerName()).'@upload'
            ];
            $this->routeWhiteLst = array_merge($whiteLst,$this->routeWhiteLst);
            //验证访问权限
            $this->checkMenuAuth();
            //验证数据范围权限
            if ($this->scopeWhere) {
                $this->scopeOrg();
            }
            parent::init();
        } catch (Exception $e) {
            $this->apiError($e->getMessage());
        }
    }

    /**
     * 验证权限
     * @return void
     * @throws Exception
     */
    private function checkMenuAuth(): void
    {
        $module_name = $this->getModuleName();
        if (!in_array($module_name,['Admin','Api','Config'])) $this->apiError("未授权，请联系管理员");
        $controller_name = $this->getRequest()->getControllerName();
        $action_name = $this->getRequest()->getActionName();
        $permission = strtolower($controller_name."@".$action_name);
        $permission_mark = Redis::getRedis()->get("backendPermissions-".$this->user->uuid);
        if (!$permission_mark) {
            $roleIds = $this->user->role->pluck("role_id")->toArray();
            $permission_id = RoleHasPermissionModel::query()->whereIn("role_id",$roleIds)->get()->pluck("permission_id");
            $permission_mark = PermissionModel::query()->whereIn("id",$permission_id)->get()->pluck("permission_mark")->toArray();
            Redis::getRedis()->set("backendPermissions-".$this->user->uuid,$permission_mark);
        }
        $permission_mark = array_merge($permission_mark,$this->routeWhiteLst);
        if (!in_array($permission, $this->routeWhiteLst)) {
            $menuList = array_format(get_no_hid("permissions"), 'permission_mark');
            $actionMenu = $menuList[$permission] ?? [];
            OperateLogModel::insert([
                'uuid' => (string)Str::uuid(),
                'user_id' => $this->member_id,
                'username' => $this->token['nickname'],
                'menu_id' => $actionMenu['id'] ?? '',
                'url' => strtolower($module_name) . "/" . strtolower($controller_name) . "/" . strtolower($action_name),
                'title' => isset($actionMenu['id'])?$this->crumbs(get_no_hid("permissions"), $actionMenu['id']).$actionMenu['permission_name']:"未授权操作",
                'action' => $action_name,
                'method'=>Request::instance()->getMethod(),
                'data' => json_encode(Request::all()),
                'ip' => get_client_ip(),
                'browser_type' => getBrowser(),
                'system_type' => getOs(),
                "status" => in_array($permission, $permission_mark) ? "success" : "error",
                'ip_address' => getIpAddress()['address']??"",
                'created_at' => date("Y-m-d H:i:s")
            ]);
        }
        if (!in_array($permission, $permission_mark)) $this->apiError("您没有权限操作，请联系管理员");
    }

    /**
     * 获取模型
     * @return string
     */
    protected function getModelMame(): string
    {
        return ucfirst($this->model)."Model";
    }

    /**
     * 获取表名
     * @return string
     * @throws TypeError
     */
    protected function getTableName(): string
    {
        $config = new Ini(__ROOT__ . "/conf/db.ini");
        $db = $config->get("db");
        return $db->prefix.$this->table;
    }

    /**
     * 获取用户数据范围
     * @param int $data_range
     * @return array
     */
    protected function userAuthOrgData(int $data_range): array
    {
        // 全部数据:1;仅自己:0;所属组织:2;所属组织及以下:3;自定义:4
        if ($data_range==0) {  //仅自己:0
            $exits = DB::schema()->hasColumn($this->table, "user_id");
            if ($exits) {
                $this->where[] = [$this->table.'.user_id','=',$this->member_id];
            }
            return [];
        }else {
            if ($data_range == 2) { //所属组织:2
                $org_id = OrganizationUserModel::query()->where("user_id", $this->member_id)
                    ->get()->pluck("organization_id")->toArray();
            } else if ($data_range == 3) { //所属组织及以下:3
                $org_id = OrganizationUserModel::query()->where("user_id", $this->member_id)
                    ->get()->pluck("organization_id")->toArray();
                $org_ids = OrganizationModel::query()->whereIn("parent_id", $org_id)->get()->pluck("id")->toArray();
                $org_id = array_merge($org_id, $org_ids);
            } else if ($data_range == 4) { //自定义:4
                $role_id = $this->user->role->pluck("role_id")->toArray();
                $org_id = RoleHasOrganizationModel::query()
                    ->whereIn("role_id", $role_id)
                    ->get()->pluck("org_id")->toArray();
            }else {
                //全部数据:1
                return [];
            }
            return $org_id;
        }
    }

    /**
     * 验证数据范围权限
     * @return array
     */
    protected function scopeOrg(): array
    {
        $orgId = [];
        //验证数据范围权限
        if (DB::schema()->hasColumn($this->table, "org_id")) {
            if (!$this->user) return [1];
            // 全部数据:1;仅自己:0;所属组织:2;所属组织及以下:3;自定义:4
            $roleId = $this->user->role->pluck("role_id")->toArray();
            $data_range = RoleModel::query()->whereIn("id",$roleId)->get()->pluck("data_range")->toArray();
            foreach ($data_range as $value) {
                $org_id = $this->userAuthOrgData((int)$value);
                if ($org_id) $orgId = array_merge($org_id, $orgId);
            }
            if ($orgId  && $this->scopeWhere) {
                $this->whereIn[] = [$this->table.'.org_id', $orgId];
            }
        }
        return $orgId;
    }

    /**
     * 获取列表页数据
     * @return void
     */
    #[NoReturn] public function indexAction(): void
    {
        try {
            $sort = Request::input("sort");
            $orderBy = match ($sort)
            {
                "-id"=>'asc',
                default => 'desc',
            };
            if (Request::input("is_hid") !== null) {
                $this->where[] = ['is_hid','=',Request::input("is_hid")];
            }
            if (isset($this->where['sorts'])) {
                $sorts = $this->where['sorts'];
                unset($this->where['sorts']);
            }else{
                $sorts = NULL;
            }
            $sql = App::make($this->getModelMame())->when($this->includes,function ($query,$value) {
                $query->with($value);
            })->where($this->where);

            $sql->when($this->whereFunction,function ($query,$value){
                $query->where($value);
            });

            $sql->when($this->whereIn,function ($query,$value){
                foreach ($value as $item) {
                    $query->whereIn($item[0], $item[1]);
                }
            });

            if (Request::input("time")) {
                if (is_array(Request::input("time"))) {
                    $sql->whereBetween("created_at",Request::input("time"));
                }else {
                    $sql->whereDate("created_at",Request::input("time"));
                }
            }
            $sql->when($sorts,function ($query,$value){
               $query->orderBy("sort",$value);
            });
            unset($this->where['sorts']);
            $data = $sql->orderBy("id",$orderBy)->paginate(Request::input("limit",10),['*'],NULL,Request::input("p",1));
            $result = [
                'items' => collect($data->items())->toArray(),
                'total'=>$data->total(),
                'per_page' => $data->perPage(),
                'page' => $data->currentPage()
            ];
            $this->apiSuccess($result,"获取成功",20000);
        }catch (Exception $e) {
            $this->apiError($e->getMessage());
        }
    }

    /**
     * 添加
     * @return void
     */
    #[NoReturn] public function addAction(): void
    {
        if (Request::instance()->isPost()) {
            $this->update();
        } else {
            $this->operate();
        }
    }

    /**
     * 编辑
     * @return void
     */
    #[NoReturn] public function editAction(): void
    {
        if (Request::instance()->isPost()||Request::instance()->isPut()) {
            $this->update();
        } else {
            $this->operate();
        }
    }

    /**
     * 显示
     * @return void
     */
    #[NoReturn] protected function operate(): void
    {
        if (!class_exists($this->getModelMame())) $this->apiError($this->getModelMame()."模型不存在");
        try {
            $info = App::make($this->getModelMame())->where('id', Request::input("ids"))->first();
            if (!$info) $this->apiError("数据不存在");
            $this->apiSuccess($info->toArray(),"获取成功",20000);
        }catch (Exception $e) {
            $this->apiError($e->getMessage());
        }
    }

    /**
     * 修改
     * @return void
     */
    protected function update(): void
    {
        try {
            $params  = Request::all();
            $this->cleanCache();
            if (Request::input("id") !== null) {
                App::make($this->getModelMame())->where("id",Request::input("id"))->update($params);
                $this->apiSuccess([],"更新成功",20000);
            }else {
                $params['uuid'] = (string)Str::uuid();
                $params['created_at'] = date("Y-m-d H:i:s");
                if (DB::schema()->hasColumn($this->table, "org_id")) {
                    $params['org_id'] = $this->org['id'];
                }
                if (DB::schema()->hasColumn($this->table, "user_id")) {
                    $params['user_id'] = $this->member_id;
                }
                $res =  App::make($this->getModelMame())->insertGetId($params);
                $info =  App::make($this->getModelMame())->where('id',$res)->first();
                $this->apiSuccess( $info->toArray(),"新增成功",20000);
            }
        } catch (Exception $e) {
            $this->apiError($e->getMessage());
        }
    }

    /**
     * 启用
     * @return void
     */
    #[NoReturn] public function enableAction(): void
    {
        $this->changeFieldValue('is_hid', 0,"启用成功");
    }

    /**
     * 禁用
     * @return void
     */
    #[NoReturn] public function disableAction(): void
    {
        $this->changeFieldValue('is_hid', 1,"禁用成功");
    }

    /**
     * 删除
     * @return void
     */
    #[NoReturn] public function delAction(): void
    {
        $this->changeFieldValue('deleted_at', date("Y-m-d H:i:s"));
    }

    /**
     * 更新单个字段，可批量，主键ID，对应参数IDS
     * @param string $field 字段名
     * @param string|int|null $value
     * @param string $msg
     * @return void
     */
    protected function changeFieldValue(string $field = '', string|int $value = null,string $msg = "操作成功"):void
    {
        if (!$field) $this->apiError('参数错误');
        $ids = Request::input("ids");
        if (empty($ids)) $this->apiError('请选择要操作的数据!');
        try {
            $value = is_null($value) ? intval(I($field)) : $value;
            if (is_array($ids)) {
                $res = App::make($this->getModelMame())
                    ->whereIn( App::make($this->getModelMame())->getKeyName(),$ids)
                    ->update([$field=>$value]);
            } else {
                $res = App::make($this->getModelMame())
                    ->where( App::make($this->getModelMame())->getKeyName(),$ids)
                    ->update([$field=>$value]);
            }
        }catch (Exception $e) {
            $this->apiError($e->getMessage());
        }
        if (!is_numeric($res)) $this->apiError($res);
        $this->cleanCache();
        $this->apiSuccess([],$msg,20000);
    }

    /**
     * 清除缓存
     * @return void
     */
    public function cleanCache():void
    {
        try {
            fileStorage($this->getTableName() . '_no_del', null);
            fileStorage($this->getTableName() . '_no_hid', null);
        } catch (Exception $e) {
            $this->apiError($e->getMessage());
        }
    }

    /**
     * 生成面包屑
     * @需求：通过ID获取所有父级数据
     * @param array $data 数据
     * @param int $id 节点ID
     * @return string $result 结果数组
     */
    protected function crumbs(array $data, int $id): string
    {
        $result = [];
        $crumbs = '';
        if (isset($data[$id]['parent_id'])) {
            while ($data[$id]['parent_id']) {
                $result[] = $data[$id]['parent_id'];
                $id = $data[$id]['parent_id'];
            }
        }
        $result = array_reverse($result);
        if ($result) {
            foreach ($result as $vo) {
                $crumbs.=$data[$vo]['permission_name'].">";
            }
        }
        return $crumbs;
    }
}
